/**
 * メモリ関係のテンプレート
 *
 * コードが汚いのは気にしない。コンパイラは信じるな。mmx/sseなんてｼﾗﾈ､128bitってなに?
 *
 * License: Public Domain
 */
module nazo.mem;
import std.stdio;

void memcpy(int T)(void* to, const(void)* from){
  static if(T!=0){
    static if(T%2==1){
      *cast(byte*)to=*cast(byte*)from;
      static if(T > 1){to++;from++;}
    }
    static if(T%4>=2){
      *cast(short*)to=*cast(short*)from;
      static if(T > 3){to+=2;from+=2;}
    }
    static if(T%8>=4){
      *cast(int*)to=*cast(int*)from;
      static if(T > 7){to+=4;from+=4;}
    }
    static if(T < 8){
    }else static if(T == 8){
      *cast(long*)to=*cast(long*)from;
    }else{
      for(int i=0;i<(T/8-1);i++){
        *cast(long*)to=*cast(long*)from;
        to+=8;from+=8;
      }
      *cast(long*)to=*cast(long*)from;
    }
  }
}

void memzero(int T)(void* dst){
  static if(T!=0){
    static if(T%2==1){
      *cast(ubyte*)dst=0;
      static if(T > 1){dst++;}
    }
    static if(T%4>=2){
      *cast(ushort*)dst=0;
      static if(T > 3){dst+=2;}
    }
    static if(T%8>=4){
      *cast(uint*)dst=0;
      static if(T > 7){dst+=4;}
    }
    static if(T < 8){
    }else static if(T == 8){
      *cast(ulong*)dst=0;
    }else{
      for(int i=0;i<(T/8-1);i++){
        *cast(ulong*)dst=0;
        dst+=8;
      }
      *cast(ulong*)dst=0;
    }
  }
}

void memset_ubyte(int T, ubyte U)(void* dst){
  static if(T!=0){
    static if(T%2==1){
      *cast(ubyte*)dst=toMultiArr_ubyte!(ubyte,U);
      static if(T > 1){dst++;}
    }
    static if(T%4>=2){
      *cast(ushort*)dst=toMultiArr_ubyte!(ushort,U);
      static if(T > 3){dst+=2;}
    }
    static if(T%8>=4){
      *cast(uint*)dst=toMultiArr_ubyte!(uint,U);
      static if(T > 7){dst+=4;}
    }
    static if(T < 8){
    }else static if(T == 8){
      *cast(ulong*)dst=toMultiArr_ubyte!(ulong,U);
    }else{
      for(int i=0;i<(T/8-1);i++){
        *cast(ulong*)dst=toMultiArr_ubyte!(ulong,U);
        dst+=8;
      }
      *cast(ulong*)dst=toMultiArr_ubyte!(ulong,U);
    }
  }
}

void memset_ushort(int T, ushort U)(void* dst){
  static assert(T%2 == 0);
  static if(T!=0){
    static if(T%4>=2){
      *cast(ushort*)dst=toMultiArr_ushort!(ushort,U);
      static if(T > 3){dst+=2;}
    }
    static if(T%8>=4){
      *cast(uint*)dst=toMultiArr_ushort!(uint,U);
      static if(T > 7){dst+=4;}
    }
    static if(T < 8){
    }else static if(T == 8){
      *cast(ulong*)dst=toMultiArr_ushort!(ulong,U);
    }else{
      for(int i=0;i<(T/8-1);i++){
        *cast(ulong*)dst=toMultiArr_ushort!(ulong,U);
        dst+=8;
      }
      *cast(ulong*)dst=toMultiArr_ushort!(ulong,U);
    }
  }
}

void memset_uint(int T, uint U)(void* dst){
  static assert(T%4 == 0);
  static if(T==0)return;
  else{
    static if(T%8>=4){
      *cast(uint*)dst=toMultiArr_uint!(uint,U);
      static if(T > 7){dst+=4;}
    }
    static if(T < 8){
    }else static if(T == 8){
      *cast(ulong*)dst=toMultiArr_uint!(ulong,U);
    }else{
      for(int i=0;i<(T/8-1);i++){
        *cast(ulong*)dst=toMultiArr_uint!(ulong,U);
        dst+=8;
      }
      *cast(ulong*)dst=toMultiArr_uint!(ulong,U);
    }
  }
}

void memset_ulong(int T, ulong U)(void* dst){
  static assert(T%8 == 0);
  static if(T!=0){
    static if(T < 8){
    }else static if(T == 8){
      *cast(ulong*)dst=toMultiArr_ulong!(ulong,U);
    }else{
      for(int i=0;i<(T/8-1);i++){
        *cast(ulong*)dst=toMultiArr_ulong!(ulong,U);
        dst+=8;
      }
      *cast(ulong*)dst=toMultiArr_ulong!(ulong,U);
    }
  }
}

template toMultiArr_ubyte(T,ubyte U){
  static if(is(T==ubyte)){
    invariant T toMultiArr_ubyte = U;
  }else static if(is(T==ushort)){
    invariant T toMultiArr_ubyte = cast(ushort)U<<8 | U;
  }else static if(is(T==uint)){
    invariant T toMultiArr_ubyte = cast(uint)U<<24 | cast(uint)U<<16 | cast(ushort)U<<8 | U;
  }else static if(is(T==ulong)){
    invariant T toMultiArr_ubyte = cast(ulong)U<<56 | cast(ulong)U<<48 | cast(ulong)U<<40 | cast(ulong)U<<32 | cast(uint)U<<24 | cast(uint)U<<16 | cast(ushort)U<<8 | U;
  }
}

template toMultiArr_ushort(T,ushort U){
  static if(is(T==ushort)){
    invariant T toMultiArr_ushort = U;
  }else static if(is(T==uint)){
    invariant T toMultiArr_ushort = cast(uint)U<<16 | U;
  }else static if(is(T==ulong)){
    invariant T toMultiArr_ushort = cast(ulong)U<<48 | cast(ulong)U<<32 | cast(uint)U<<16 | U;
  }
}

template toMultiArr_uint(T,uint U){
  static if(is(T==uint)){
    invariant T toMultiArr_uint = U;
  }else static if(is(T==ulong)){
    invariant T toMultiArr_uint = cast(ulong)U<<32 | U;
  }
}

template toMultiArr_ulong(T,ulong U){
  static if(is(T==ulong)){
    invariant T toMultiArr_ulong = U;
  }
}

unittest{
  char[] a="abcdefghijklmnopqrstuvwxyz".dup;
  memcpy!(15)(a.ptr,a.ptr+1);
  assert(a == "bcdefghijklmnoppqrstuvwxyz");
  ubyte[100] b=void;
  memzero!(b.length*b[0].sizeof)(b.ptr);
  foreach(ubyte i;b){
    if(i!=0)assert(0);
  }
  ubyte[100] c=void;
  memset_ubyte!(c.length*c[0].sizeof,100)(c.ptr);
  foreach(ubyte i;c){
    if(i!=100)assert(0);
  }
  ushort[100] d=void;
  memset_ushort!(d.length*d[0].sizeof,100)(d.ptr);
  foreach(ushort i;d){
    if(i!=100)assert(0);
  }
  uint[100] e=void;
  memset_uint!(e.length*e[0].sizeof,100)(e.ptr);
  foreach(uint i;e){
    if(i!=100)assert(0);
  }
  ulong[100] f=void;
  memset_ulong!(f.length*f[0].sizeof,100)(f.ptr);
  foreach(ulong i;f){
    if(i!=100)assert(0);
  }
}
